package org.bigk.invoices.services;

import java.util.Calendar;
import java.util.Date;
import java.util.List;

import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.math.NumberUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.bigk.invoices.exceptions.ServiceException;
import org.bigk.invoices.model.PaymentKind;
import org.bigk.invoices.utils.HibernateUtils;
import org.hibernate.Criteria;
import org.hibernate.HibernateException;
import org.hibernate.Session;

public class PaymentKindsServiceImpl implements PaymentKindsService {
	/**
	 * Logger for this class
	 */
	private static final Log logger =
		LogFactory.getLog(PaymentKindsServiceImpl.class);

	public PaymentKindsServiceImpl() {
	}

	@SuppressWarnings("unchecked")
	public List<PaymentKind> listAllItems() throws ServiceException {
		if (logger.isDebugEnabled()) {
			logger.debug("listAllItems() - start");
		}

		List<PaymentKind> list = null;
		Session session = null;
		try {
			session = HibernateUtils.getCurrentSession();
			Criteria crit = session.createCriteria(PaymentKind.class);
			list = crit.list();
			
		} catch (HibernateException ex) {
			logger.error("listAllItems()", ex);
			throw new ServiceException(ex);
		}

		if (logger.isDebugEnabled()) {
			logger.debug("listAllItems() - end - return value=" + CollectionUtils.size(list));
		}
		return list;
	}

	public PaymentKind getPaymentKind(Long id) throws ServiceException {
		if (logger.isDebugEnabled()) {
			logger.debug("getPaymentKind(Long id=" + id + ") - start");
		}

		PaymentKind object = null;
		Session session = null;
		try {
			session = HibernateUtils.getCurrentSession();
			object = (PaymentKind) session.get(PaymentKind.class, id);
		} catch (HibernateException ex) {
			logger.error("getObject4Id(Long)", ex);
			throw new ServiceException(ex);
		}

		if (logger.isDebugEnabled()) {
			logger.debug("getPaymentKind(Long) - end - return value=" + object);
		}
		return object;
	}

	public Date calculatePaymentDate(Date soldDate, Long paymentKindId)
			throws ServiceException {
		if (logger.isDebugEnabled()) {
			logger.debug("calculatePaymentDate(Date soldDate=" + soldDate
					+ ", Long paymentKindId=" + paymentKindId + ") - start");
		}

		PaymentKind paymentKind = this.getPaymentKind(paymentKindId);
		if (paymentKind == null) {
			throw new ServiceException("No PaymentKind read for id: " + paymentKindId);
		}
		Date returnDate = calculatePaymentDate(soldDate, paymentKind.getValue());

		if (logger.isDebugEnabled()) {
			logger.debug("calculatePaymentDate(Date, Long) - end - return value=" + returnDate);
		}
		return returnDate;
	}

	public Date calculatePaymentDate(Date soldDate, String paymentKindValue)
			throws ServiceException {
		if (logger.isDebugEnabled()) {
			logger.debug("calculatePaymentDate(Date soldDate=" + soldDate
					+ ", String paymentKindValue=" + paymentKindValue
					+ ") - start");
		}
		
		Calendar cal = Calendar.getInstance();
		cal.setTime(soldDate);
		
		String formule = paymentKindValue;
		if (StringUtils.isNotBlank(formule)) {
			formule = StringUtils.lowerCase(formule);
			
			// detect 'period': one of 'd' (day) or 'm' (month)
			String period = null;
			if (formule.startsWith("d")) {
				period = "d";
				formule = formule.substring(1);
			} else if (formule.startsWith("m")) {
				period = "m";
				formule = formule.substring(1);
			}
			
			// detect 'sign': one of '+' or '-'
			int sign = 1;
			if (formule.startsWith("+"))
				formule = formule.substring(1);
			else if (formule.startsWith("-")) {
				sign = -1;
				formule = formule.substring(1);
			}

			if (logger.isDebugEnabled()) {
				logger.debug("calculatePaymentDate(Date, String) - formule="
						+ formule + ", period=" + period + ", sign=" + sign);
			}
			
			if ("d".equals(period)) {
				int days = sign * NumberUtils.toInt(formule, 0);
				cal.add(5, days);
			} else if ("m".equals(period)) {
				int months = sign * NumberUtils.toInt(formule, 0);
				cal.add(2, months);
			}
		}
		
		Date returnDate = cal.getTime();

		if (logger.isDebugEnabled()) {
			logger.debug("calculatePaymentDate(Date, String) - end - return value=" + returnDate);
		}
		return returnDate;
	}

	public static void main(String args[]) throws ServiceException {
		PaymentKindsServiceImpl service = new PaymentKindsServiceImpl();
		Calendar cal = Calendar.getInstance();
		Date date1 = cal.getTime();
		Date date2 = service.calculatePaymentDate(date1, Long.valueOf(4L));
		System.out.println(date1);
		System.out.println(date2);
	}

}
